`include "common_def.v"
`include "decode_def.v"
module MODULE_LSU(
	input			clk_i,
	input			rst_i,
	output		lsu_ready_o,
	input			LSRp_ready_i,
	input			is_fencei_i,
	output		fencei_end_o,
	//connect to reg
	input	 [`WIDTH-1:0]	store_data_i,
	output [`WIDTH-1:0] load_data_o,
	//connect to IDU
	input								read_en_i,
	input								write_en_i,
	input	 [7:0]				store_mask_i,
	input	 [`LOAD_NUM-1:0]load_data_key_i,
	input	 [2:0]				ls_size_i,
	//connect to EXU
	input  [`WIDTH-1:0]	address_i,
	//for ctr
	input								ls_start_i,
	output							ls_end_o,
	//to Dcache	
	output	[`WIDTH-1:0]	address_o,
	output								addr_r_valid_o,
	input		[`WIDTH-1:0]	load_data_i,
	input									read_end_i,
	output								addr_w_valid_o,
	output	[`WIDTH-1:0]	store_data_o,
	output	[7:0]					store_mask_o,
	input									write_end_i,
	output								is_fencei_o,
	input									fencei_end_i,
	output								is_clint_o,
	output	[2:0]					ls_size_o,
	
	//to clint
	input	 [`WIDTH-1:0]		clint_data_i,
	output								clint_w_en_o,
	output								clint_r_en_o
	
);
assign ls_size_o[2:0] = ls_size_i[2:0];
assign is_clint_o = is_clint;
wire is_clint ;
assign is_clint = (address_i[`WIDTH-1:0] <=64'h00000000_0200BFFF) &(address_i >=64'h00000000_02000000);

assign lsu_ready_o = LSRp_ready_i;
wire ls_start_r;
Reg #(1,0) ls_start_reg(clk_i,rst_i,ls_end_o ? 1'b0:ls_start_i,ls_start_r,ls_start_i|ls_end_o);
assign addr_r_valid_o= read_en_i & (ls_start_r|ls_start_i)&(~ls_end_o)&(~is_clint);
assign addr_w_valid_o= write_en_i& (ls_start_r|ls_start_i)&(~is_clint);
assign clint_r_en_o= read_en_i & (ls_start_r|ls_start_i)&(~ls_end_o);
assign clint_w_en_o= write_en_i& (ls_start_r|ls_start_i);
wire ls_end_r_or_w;
assign ls_end_r_or_w = (read_en_i | write_en_i) ? ((read_end_i)|(write_end_i))&ls_start_r : is_fencei_i ? 0 : (ls_start_i|ls_start_r); 
assign ls_end_o = ls_end_r_or_w | fencei_end_i;

assign address_o[`WIDTH-1:0] = address_i[`WIDTH-1:0];
//assign store_data_o[`WIDTH-1:0] = store_data_i[`WIDTH-1:0];
MuxKeyWithDefault #(8,3,`WIDTH) store_data_axi_mux(store_data_o[`WIDTH-1:0],address_i[2:0],0,{
	3'b000, store_data_i[`WIDTH-1:0],
	3'b001, {store_data_i[`WIDTH-9:0],8'b0},
	3'b010, {store_data_i[`WIDTH-17:0],16'b0},
	3'b011, {store_data_i[`WIDTH-25:0],24'b0}, 
	3'b100, {store_data_i[`WIDTH-33:0],32'b0}, 
	3'b101, {store_data_i[`WIDTH-41:0],40'b0}, 
	3'b110, {store_data_i[`WIDTH-49:0],48'b0}, 
	3'b111, {store_data_i[`WIDTH-57:0],56'b0} 
});
MuxKeyWithDefault #(8,3,8) store_mask_axi_mux(store_mask_o[7:0],address_i[2:0],0,{
	3'b000, store_mask_i[7:0],
	3'b001,{store_mask_i[6:0],1'b0},
	3'b010,{store_mask_i[5:0],2'b0},
	3'b011,{store_mask_i[4:0],3'b0},
	3'b100,{store_mask_i[3:0],4'b0},
	3'b101,{store_mask_i[2:0],5'b0},
	3'b110,{store_mask_i[1:0],6'b0},
	3'b111,{store_mask_i[0],7'b0}
});
//assign store_mask_o[7:0]	= store_mask_i[7:0];
assign fencei_end_o = fencei_end_i;
assign is_fencei_o = is_fencei_i;
//choose the load_data according the key from IDU
wire [`WIDTH-1:0]			load_data;
wire [`WIDTH-1:0]	load_data_before_shift;
assign load_data_before_shift[`WIDTH-1:0] = is_clint ? clint_data_i[`WIDTH-1:0] : load_data_i[`WIDTH-1:0];
MuxKeyWithDefault #(8,3,`WIDTH) load_data_mux(.out(load_data[`WIDTH-1:0]),.key(address_i[2:0]),.default_out(0),.lut({
	3'b000, load_data_before_shift[`WIDTH-1:0],
	3'b001, {8'b0,load_data_before_shift[`WIDTH-1:8]},
	3'b010, {16'b0,load_data_before_shift[`WIDTH-1:16]},
	3'b011, {24'b0,load_data_before_shift[`WIDTH-1:24]},
	3'b100, {32'b0,load_data_before_shift[`WIDTH-1:32]},
	3'b101, {40'b0,load_data_before_shift[`WIDTH-1:40]},
	3'b110, {48'b0,load_data_before_shift[`WIDTH-1:48]},
	3'b111, {56'b0,load_data_before_shift[`WIDTH-1:56]}
}));
wire [`WIDTH-1:0]     load_d_data;
wire [`WIDTH-1:0]     load_w_data;
wire [`WIDTH-1:0]     load_h_data;
wire [`WIDTH-1:0]     load_hu_data;
wire [`WIDTH-1:0]     load_bu_data;
wire [`WIDTH-1:0]     load_b_data;
wire [`WIDTH-1:0]     load_wu_data;
assign load_d_data[`WIDTH-1:0] = load_data[`WIDTH-1:0];
assign load_w_data[`WIDTH-1:0] = {{`WIDTH-32{load_data[31]}},load_data[31:0]};
assign load_h_data[`WIDTH-1:0] = {{`WIDTH-16{load_data[15]}},load_data[15:0]};
assign load_hu_data[`WIDTH-1:0] = {{`WIDTH-16{1'b0}},load_data[15:0]};
assign load_bu_data[`WIDTH-1:0] = {{`WIDTH-8{1'b0}},load_data[7:0]};
assign load_b_data[`WIDTH-1:0] = {{`WIDTH-8{load_data[7]}},load_data[7:0]};
assign load_wu_data[`WIDTH-1:0] = {{`WIDTH-32{1'b0}},load_data[31:0]};
MuxKeyWithDefault #(`LOAD_NUM,`LOAD_NUM,`WIDTH) load_data_o_mux (load_data_o[`WIDTH-1:0],load_data_key_i[`LOAD_NUM-1:0],{`WIDTH{1'b0}},{
7'b000_0001, load_w_data[`WIDTH-1:0],
7'b000_0010, load_d_data[`WIDTH-1:0],
7'b000_0100, load_bu_data[`WIDTH-1:0],
7'b000_1000, load_h_data[`WIDTH-1:0],
7'b001_0000, load_hu_data[`WIDTH-1:0],
7'b010_0000, load_b_data[`WIDTH-1:0],
7'b100_0000, load_wu_data[`WIDTH-1:0]
 });
endmodule
